#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
#

import    random
import    sha
import    socket
import    struct

NBIT = 160    # Size (in bits) of Chord identifiers

KEY_SPACE = (2 ** NBIT)

def    chordID( astring ) :
    id = sha.new( astring ).digest()
    return    id
    
class    Node( object ) :
    '''
    A node in a Chord network
    '''
    def    __init__(self, port, ip=None) :
        if ip is None :
            self.__ip = socket.gethostbyname(socket.gethostname())
        else :
            self.__ip = socket.inet_aton(ip)
        self.__port = int(port)
        
        self.__id = chordID( self.__ip + struct.pack('!h', self.__port) )
        self.__finger = [ None ] * (NBIT + 1)
        self.__predecessor = None
        self.__successor = None
        
        self.__in_ring = False
        
        # start listening 
        backlog = 10
        self.__socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
        self.__socket.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
        self.__socket.bind( ('', self.__port) )
        self.__socket.listen( backlog ) 
        # __init__()
        
    def    __repr__(self) :
        return    "<Node %s>" % (self.__id, )
        # __repr__()
        
    def    create(self) :
        if self.__in_ring : return
        
        self.__predecessor = None
        self.__successor = None
        
        self.__in_ring = True
        # create()
        
    def    join(self, node_address) :
        '''
        join a Chord ring containing node <node>
        node address is a (ip, port) tuple
        '''
        if node_address is None : return
        
        self.__in_ring = True
        # join()
        
    def    leave(self) :
        self.__in_ring = False
        # leave()
        